#ifndef __DATABASE_H__
  #define __DATABASE_H__

#include <string>

#include "record_set.h"
#include "global_variables.h"

using namespace std;

//! Database interface for database connectivity

/*!
This class is a pure virtual interface for database connectivity, which must be implemented for specific
database management systems.
The idea behind this interface is to have the same interface for connectiong to all database systems.
Internationalized data will be dealt with in UTF8 format.

Implementation date: 2008

Usage:

This class is a pure virtual interface and cannot be used alone.
*/

class database {
private:
  //! assignment operator: not allowed
  database &operator=(const database &db);

  //! copy constructor: not allowed
  database(const database &db);

protected:
  string protocol; // protocol file name, or an empty string to deactivate file protocoling
  bool connected;
  bool is_in_transaction;

  //! writes some useful information into the protocol file. this method can be called by sub-classes
  virtual void prot(const string &message, const string &statement = global_empty_string, unsigned long long duration = 0ULL, size_t items = 0) const;

public:
  //! connects to the database using the given connection_string. if the protocol_file is empty no protocolling will be done (may throw an exception)
  virtual void connect(const string &connection_string, const string &protocol_file = global_empty_string) = 0;

  //! connects to the database using the given host, user_id, password and db_name. if the protocol_file is empty no protocolling will be done (may throw an exception)
  virtual void connect(const string &host, const string &user_id, const string &password, const string &db_name, const string &protocol_file = global_empty_string) = 0; // may throw a db_exception

  //! disconnects from the database. may rollback a transaction if it is not already commited
  virtual void disconnect() = 0;

  //! returns true if connected to the database (non-const method, because sub-classes may change the value of 'connected' here)
  /*!
  this method may send extra queries to the database to make sure it is online and responding. depending on the
  database implementation queries like 'SELECT VERSION();' could be used to achieve this. please check your
  database documentation before overriding this method
  */
  virtual bool is_connected();

  //! executes an sql query for example: SELECT (may throw an exception)
  /*!
  the given string must be in UTF8 format.
  if the parameter append_to_record_set is ture, then the new records will be added to rs without clearing its existing rows
  (number of columns must stay the same).
  */
  virtual void execute_query(const string &s, record_set &rs, bool append_to_record_set = false) = 0;

  //! executes an sql statement for example: INSERT, UPDATE, DELETE (may throw an exception)
  /*!
  the given string must be in UTF8 format.
  */
  virtual void execute_update(const string &s) = 0;

  //! starts a transaction. this must be called before calling commit() or rollback()
  virtual void start_transaction() = 0;

  //! commits the transaction or does nothing if start_transaction() is not called
  virtual void commit() = 0;

  //! rollbacks the transaction or does nothing if start_transaction() is not called
  virtual void rollback() = 0;

  //! returns true if there is a transaction currently active
  virtual bool is_transaction_active() const;

  //! locks the table with the given table_name exclusively
  /*!
  the table will remain locked until unlock_table is called. this means that all other
  reads & writes to the table will be blocked. some database systems like PostgreSQL
  require a transaction to lock tables
  */
  virtual void lock_table(const string &table_name) = 0;

  //! unlocks the table with the given table_name
  /*!
  see lock_table
  */
  virtual void unlock_table(const string &table_name) = 0;

  //! default constructor
  database();

  //! destructor: sub-class must call the disconnect() in the destructor as well
  virtual ~database();
}; // class database

#endif
